﻿using System.Linq;
using CardPlay.Model.ActionModel;
using CardPlay.Model.CardModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Actions;
using CardPlay.Model.GameModel.Presentation;
using CardPlay.Model.Layout;

namespace CardPlay.DemoPack.Games.SpiderVariants
{
    [Game("CB9FB8EE-7E07-4273-A801-A0A688680C4F", LevelOfDifficulty.Hard, LevelOfSkill.ModerateSkill, DurationOfPlay.MoreThan10Minutes, Family = Spiderette.FamilyName)]
    public class LittleSpider : StandardCardGame
    {
        public LittleSpider()
        {
            MaximumDeals = 1;
            TotalTableaus = 8;
            TotalFoundations = 4;
            TableauBuildSequence = CardFaceSequence.AnySuitAdjacentRank;
        }

        public override ILayoutSite CreatePresentation(IPresentationContext presentation)
        {
            var tableauStyle = StandardStyles.Tableau;
            tableauStyle.Arrangement = CardArrangement.StackSquare;

            var foundationStyle = StandardStyles.Foundation;
            foundationStyle.UpdateBaseCues = (pile, cues) =>
            {
                var updateRightGroup = pile.GetOrdinal() > 2;

                cues.SetRankCue(updateRightGroup ? Rank.King : Rank.Ace);

                var expectedSuitColor = FoundationSuitColorOf(pile);

                if (!expectedSuitColor.HasValue)
                {
                    cues.SetFoundationSuitCue(this, AnyFoundation);
                }
                else
                {
                    var subGroup = this.NonEmptyPilesNamed(StandardPileNames.RangePatternForFoundations(updateRightGroup ? 3 : 1, 2));
                    cues.SetFoundationSuitCue(subGroup, expectedSuitColor.Value.MatchingSuits());
                }
            };


            var upperRow = presentation.CreateRowLayout();
            presentation.AddPiles(upperRow, NamesOfTableaus.Take(4), tableauStyle);

            var foundations = presentation.CreateRowLayout();
            presentation.AddPiles(foundations, NamesOfFoundations, foundationStyle);

            var lowerRow = presentation.CreateRowLayout();
            presentation.AddPiles(lowerRow, NamesOfTableaus.Skip(4), tableauStyle);

            var column = presentation.CreateColumnLayout();
            column.Add(upperRow);
            column.Add(foundations);
            column.Add(lowerRow);

            var root = presentation.CreateRowLayout();
            root.Add(presentation.CreatePileVisual(Stock, presentation.StyleForStock(this)));
            root.Add(column);

            return root;
        }

        protected override void PrepareDealScript(DealScript script)
        {
            script.DealRemainingFaceDownTo(Stock);
        }

        protected override IAction QueryActionAt(PartLocation location)
        {
            var card = CardAt(location);

            if (card == null) return null;

            return location.Matches(Stock) && location == this[Stock].Top
                ? new DealOutTableauAction(this, location)
                : base.QueryActionAt(location);
        }

        protected override bool AllowedToPickupAtTableau(RemovePileAction action)
        {
            return action.IsActingOnFaceUpTopCard();
        }

        protected override bool AllowedToBuildFoundation(MovePileAction action)
        {
            if (!IsStockDealt && action.SourcePile.Location.Matches(StandardPileNames.RangePatternFor(StandardPileNames.PrefixForTableau, 5, 4)))
            {
                var sourceIndex = action.SourcePile.GetOrdinal();
                var targetIndex = action.TargetPile.GetOrdinal();

                if (sourceIndex - 4 != targetIndex)
                    return false;
            }

            var isBuildingDown = action.TargetPile.GetOrdinal() > 2;

            if (action.TargetPile.IsEmpty)
            {
                var expectedSuitColor = FoundationSuitColorOf(action.TargetPile);

                if (expectedSuitColor.HasValue && action.PileBeingMoved.BottomCard.Face.Suit.Color() != expectedSuitColor)
                    return false;
            }

            return
                action.IsMovingSingleCard() &&
                isBuildingDown ? action.IsBuildingDescendingFoundation() : action.IsBuildingAscendingFoundation();
        }

        protected override bool AllowedToBuildEmptyTableau(MovePileAction action)
        {
            return false;
        }

        protected override bool AllowedToBuildNonEmptyTableau(MovePileAction action)
        {
            return IsStockDealt && action.IsBuilding(TableauBuildSequence);
        }

        private SuitColor? FoundationSuitColorOf(CardPile pile)
        {
            var isFoundationSuitOnRightRed = IsFoundationSuitOnRightRed;
            if (! isFoundationSuitOnRightRed.HasValue) return null;

            var isPileOnRight = pile.GetOrdinal() > 2;
            return isPileOnRight == isFoundationSuitOnRightRed ? SuitColor.Red : SuitColor.Black;
        }

        private bool? IsFoundationSuitOnRightRed
        {
            get
            {
                if (!this.NonEmptyPilesNamed(AnyFoundation).Any()) return null;

                var pairL = this.NonEmptyPilesNamed(StandardPileNames.RangePatternForFoundations(1, 2));
                var pairR = this.NonEmptyPilesNamed(StandardPileNames.RangePatternForFoundations(3, 2));

                return 
                    pairL.Any(foundation => foundation.BottomCard.Face.Suit.Color() == SuitColor.Black) ||
                    pairR.Any(foundation => foundation.BottomCard.Face.Suit.Color() == SuitColor.Red);
            }
        }

        private bool IsStockDealt
        {
            get { return this[Stock].IsEmpty; }
        }
    }
}